/**  
 * @author renbangjie renbangjie@126.com  
 * @date 2014-11-27 上午11:28:08
 * @version V1.0  
 * <b>Copyright (c)</b> 2014医信金融信息服务（上海）有限公司-版权所有<br/>
 */
package com.yjd.comm.pay.util;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Map;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.params.HttpConnectionParams;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.lang3.StringUtils;

import com.yjd.comm.pay.model.GoPayOrder;
import com.yjd.comm.util.FrameUtil;

/**
 * 国付宝充值接口工具类
 * 
 * @author renbangjie renbangjie@126.com
 * @date 2014-11-27 上午11:28:08
 */
public class GoPayUtils extends FrameUtil {

	private static final String COMMON_DATE = "yyyyMMddHHmmss";

	// private static final String MARK = "YJD";

	/**
	 * 判断交易来源是否是国付宝
	 * 
	 * @param paramMap
	 * @return boolean
	 * @throws Exception
	 */
	public static boolean authentication(Map<String, Object> paramMap)
			throws Exception {
		// 国付宝返回参数
		GoPayOrder goPayOrder = GoPayUtils.parseCallBackOrder(paramMap);
		// 生成国付宝签名
		String signatrue = GoPayUtils.generateCallBackSignature(goPayOrder);

		return signatrue.compareTo(goPayOrder.getSignValue()) == 0;
	}

	/**
	 * 生成国付宝订单
	 * 
	 * @param time
	 *            交易日期
	 * @param transID
	 *            交易号
	 * @param orderMoney
	 *            订单金额
	 * @param ip
	 *            用户浏览器ip
	 * @param bankCode
	 *            银行编码
	 * @param bankType
	 *            1为个人网银 2为企业网银
	 * @return GoPayOrder
	 */
	public static GoPayOrder generateOrder(Date time, String transID,
			double orderMoney, String ip, String bankCode, String bankType,
			String goodsName) {
		GoPayOrder goPayOrder = GoPayUtils.getConfig();

		// String sysid = MARK + transID;
		goPayOrder.setMerOrderNum(goPayOrder.getMerchantID() + "-" + transID); // 订单号
		goPayOrder.setTranAmt(String.valueOf(orderMoney)); // 交易金额（按元计算）
		goPayOrder.setFeeAmt("0"); // 商户提取佣金金额
		goPayOrder.setTranDateTime(new SimpleDateFormat(COMMON_DATE,
				Locale.CHINA).format(time)); // 交易时间
		goPayOrder.setTranIP(ip);// 浏览器ip
		goPayOrder.setIsRepeatSubmit("1"); // 是否允许重复提交 1为允许，默认为1
		goPayOrder.setBankCode(bankCode);
		goPayOrder.setUserType(bankType); // 企业网银或个人网银 1为个人 2为企业
		goPayOrder.setGoodsName(goodsName);
		String timestrap = GoPayUtils.getServerTime();
		goPayOrder.setGopayServerTime(timestrap);

		String signature = GoPayUtils.getSignature(goPayOrder);
		goPayOrder.setSignValue(signature);

		return goPayOrder;
	}

	/**
	 * 生成国付宝返回签名
	 * 
	 * @param paramMap
	 * @param order
	 * @return String
	 */
	private static String generateCallBackSignature(GoPayOrder order) {
		StringBuffer sb = new StringBuffer();
		sb.append("version=").append("[").append(order.getProtocolVersion())
				.append("]").append("tranCode=").append("[")
				.append(order.getTranCode()).append("]").append("merchantID=")
				.append("[").append(order.getMerchantID()).append("]")
				.append("merOrderNum=").append("[")
				.append(order.getMerOrderNum()).append("]").append("tranAmt=")
				.append("[").append(order.getTranAmt()).append("]")
				.append("feeAmt=").append("[").append(order.getFeeAmt())
				.append("]").append("tranDateTime=").append("[")
				.append(order.getTranDateTime()).append("]")
				.append("frontMerUrl=").append("[")
				.append(order.getFrontMerUrl()).append("]")
				.append("backgroundMerUrl=").append("[")
				.append(order.getBackgroundMerUrl()).append("]")
				.append("orderId=").append("[").append(order.getOrderId())
				.append("]").append("gopayOutOrderId=").append("[")
				.append(order.getGopayOutOrderId()).append("]")
				.append("tranIP=").append("[").append(order.getTranIP())
				.append("]").append("respCode=").append("[")
				.append(order.getRespCode()).append("]")
				.append("gopayServerTime=[]").append("VerficationCode=")
				.append("[").append(order.getVerficationCode()).append("]");
		return DigestUtils.md5Hex(getBytes(sb.toString()));
	}

	/**
	 * 国付宝回调参数转换为国付宝订单对象
	 * 
	 * @param paramMap
	 * @return GoPayOrder
	 */
	public static GoPayOrder parseCallBackOrder(Map<String, Object> paramMap) {
		String verficationCode = GoPayUtils.getConfig().getVerficationCode();

		GoPayOrder order = new GoPayOrder();
		order.setProtocolVersion((String) paramMap.get("version"));
		order.setCharset((String) paramMap.get("charset"));
		order.setLanguage((String) paramMap.get("language"));
		order.setSignType((String) paramMap.get("signType"));
		order.setTranCode((String) paramMap.get("tranCode"));
		order.setMerchantID((String) paramMap.get("merchantID"));
		order.setMerOrderNum((String) paramMap.get("merOrderNum"));
		order.setTranAmt((String) paramMap.get("tranAmt"));
		order.setFeeAmt((String) paramMap.get("feeAmt"));
		order.setFrontMerUrl((String) paramMap.get("frontMerUrl"));
		order.setBackgroundMerUrl((String) paramMap.get("backgroundMerUrl"));
		order.setTranDateTime((String) paramMap.get("tranDateTime"));
		order.setTranFinishTime((String) paramMap.get("tranFinishTime"));
		order.setTranIP((String) paramMap.get("tranIP"));
		order.setBankCode((String) paramMap.get("bankCode"));
		order.setSignValue((String) paramMap.get("signValue"));
		order.setVerficationCode(verficationCode);

		order.setOrderId((String) paramMap.get("orderId"));
		order.setGopayOutOrderId((String) paramMap.get("gopayOutOrderId"));
		order.setRespCode((String) paramMap.get("respCode"));

		return order;
	}

	private static final String MARK = "YJD";
	
	/**
	 * 解析订单号
	 * 
	 * @param transID
	 * @return Long
	 * @throws Exception
	 */
	public static Long getOrderID(String transID) throws Exception {
		if (StringUtils.isBlank(transID)) {
			FrameUtil.throwBaseException1("交易流水号异常");
		}
		//兼容旧版本的订单号
		if(!transID.contains("-")){
			String sid = transID.replaceFirst(MARK, "");
			if(StringUtils.isBlank(sid)){
				throw new Exception("订单号异常");
			}
			return Long.valueOf(sid);
		}
		
		String temp = GoPayUtils.getConfig().getMerchantID() + "-";
		if (!transID.contains(temp)) {
			return null;
		}
		String sid = transID.replaceFirst(temp, "");
		if (StringUtils.isBlank(sid) || !NumberUtils.isNumber(sid)) {
			throw new Exception("订单号异常");
		}
		return Long.valueOf(sid);
	}

	/**
	 * 设置签名字段
	 * 
	 * @param order
	 * @return String
	 */
	private static String getSignature(GoPayOrder order) {
		StringBuffer sb = new StringBuffer();
		sb.append("version=").append("[").append(order.getProtocolVersion())
				.append("]").append("tranCode=").append("[")
				.append(order.getTranCode()).append("]").append("merchantID=")
				.append("[").append(order.getMerchantID()).append("]")
				.append("merOrderNum=").append("[")
				.append(order.getMerOrderNum()).append("]").append("tranAmt=")
				.append("[").append(order.getTranAmt()).append("]")
				.append("feeAmt=").append("[").append(order.getFeeAmt())
				.append("]").append("tranDateTime=").append("[")
				.append(order.getTranDateTime()).append("]")
				.append("frontMerUrl=").append("[")
				.append(order.getFrontMerUrl()).append("]")
				.append("backgroundMerUrl=").append("[")
				.append(order.getBackgroundMerUrl()).append("]")
				.append("orderId=[]").append("gopayOutOrderId=[]")
				.append("tranIP=").append("[").append(order.getTranIP())
				.append("]").append("respCode=[]").append("gopayServerTime=")
				.append("[").append(order.getGopayServerTime()).append("]")
				.append("VerficationCode=").append("[")
				.append(order.getVerficationCode()).append("]");
		return DigestUtils.md5Hex(getBytes(sb.toString()));
	}

	/**
	 * 获取国付宝的时间戳
	 * 
	 * @return String
	 */
	private static String getServerTime() {
		GoPayOrder goPayOrder = GoPayUtils.getConfig();

		HttpClient httpClient = new HttpClient();
		httpClient.getParams().setCookiePolicy(CookiePolicy.RFC_2109);
		httpClient.getParams().setIntParameter(HttpConnectionParams.SO_TIMEOUT,
				10000);

		GetMethod getMethod = new GetMethod(goPayOrder.getTimestampURL());
		getMethod.getParams().setParameter(
				HttpMethodParams.HTTP_CONTENT_CHARSET, "GBK");
		// 执行getMethod
		int statusCode = 0;
		try {
			statusCode = httpClient.executeMethod(getMethod);
			if (statusCode == HttpStatus.SC_OK) {
				String respString = StringUtils.trim((new String(getMethod
						.getResponseBody(), "GBK")));
				return respString;
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			getMethod.releaseConnection();
		}
		return null;
	}

	/**
	 * 获取支付接口配置信息
	 * 
	 * @return GoPayOrder
	 */
	private static GoPayOrder getConfig() {
		// 读取配置文件中的配置
		String verficationCode = getConstResource("gopay.verficationCode");
		String version = getConstResource("gopay.version");
		String charset = getConstResource("gopay.charset");
		String language = getConstResource("gopay.language");
		String signType = getConstResource("gopay.signType");
		String tranCode = getConstResource("gopay.tranCode");
		String merchantID = getConstResource("gopay.merchantID");
		String currencyType = getConstResource("gopay.currencyType");
		String virCardNoIn = getConstResource("gopay.virCardNoIn");
		String payUrl = getConstResource("gopay.payUrl");
		String timestampURL = getConstResource("gopay.timestamp");
		String pageUrl = getConstResource("gopay.pageUrl");
		String returnUrl = getConstResource("gopay.returnUrl");

		GoPayOrder goPayOrder = new GoPayOrder();
		goPayOrder.setVerficationCode(verficationCode);
		goPayOrder.setProtocolVersion(version);
		goPayOrder.setCharset(charset);
		goPayOrder.setLanguage(language);
		goPayOrder.setSignType(signType);
		goPayOrder.setTranCode(tranCode);
		goPayOrder.setMerchantID(merchantID);
		goPayOrder.setCurrencyType(currencyType);
		goPayOrder.setVirCardNoIn(virCardNoIn);
		goPayOrder.setPayUrl(payUrl);
		goPayOrder.setTimestampURL(timestampURL);
		goPayOrder.setPayUrl(payUrl);
		goPayOrder.setBackgroundMerUrl(returnUrl);
		goPayOrder.setFrontMerUrl(pageUrl);

		return goPayOrder;
	}

	/**
	 * 签名字段加密
	 * 
	 * @return byte[]
	 */
	private static byte[] getBytes(String pain) {
		try {
			return pain.getBytes("utf-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return null;
	}

}
